# -*- coding: utf-8 -*-
import cv2
import sys

sys.setrecursionlimit(50000)  # 最大递归深度为十万

def get_neighbours(i, j, h, w):
    neighbours = []
    for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1)]:  # 只考虑4个方向
        ni, nj = i + di, j + dj
        if 0 <= ni < h and 0 <= nj < w:
            neighbours.append((ni, nj))
    return neighbours


# 种子填充法, 搜索周围邻域, 找出也是前景色(白色)的像素, 赋值为索引色index
def seed_filling(img, i, j, new_color):
    h, w = img.shape[:2]
    stack = [(i, j)]  # 使用栈存储待处理的像素坐标
    img[i, j] = new_color  # 标记当前像素为索引色

    while stack:
        i, j = stack.pop()
        for ni, nj in get_neighbours(i, j, h, w):
            if img[ni, nj] == 255:  # 如果相邻像素是前景色(白色)
                img[ni, nj] = new_color  # 标记为索引色
                stack.append((ni, nj))  # 将相邻像素加入栈中


################### 主程序流程 #######################
# 1.读取图像, 转为灰度图像
img = cv2.imread("coins.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imshow('img_gray', img_gray)

# 2.对灰度图像做均值滤波
img_gray = cv2.blur(img_gray, (10, 10))
# cv2.imshow('img_blur', img_gray)

# 3.选择合适阈值, 将滤波后的图像二值化, 硬币区域为白色, 背景为黑色
t, img_bin = cv2.threshold(img_gray, 120, 255, cv2.THRESH_BINARY)
# cv2.imshow('img_bin', img_bin)

# 4.初始化
h, w = img_bin.shape
idx_color = 50   # 硬币的初始颜色索引, 50,80,110,140 ...
ls_idx = []      # 索引色列表

# 5.对图像所有的像素做遍历
for i in range(h):
    for j in range(w):
        if img_bin[i, j] == 255:                  # 如果当前像素是前景色(白色)
            seed_filling(img_bin, i, j, idx_color) # 搜寻相邻连通区域, 若也是前景色则填充索引色idx_color
            ls_idx.append(idx_color)              # 索引色加入列表
            idx_color += 30                       # 当前硬币处理结束, 索引色递增

# 6.显示最终效果和硬币数量
cv2.imshow('img_index', img_bin)
print("硬币个数为:", len(ls_idx))
print("硬币索引色分别为:", ls_idx)

cv2.waitKey()
cv2.destroyAllWindows()
